package com.ydlclass.watch;

import com.ydlclass.NettyBootstrapInitializer;
import com.ydlclass.YrpcBootstrap;
import com.ydlclass.discovery.Registry;
import com.ydlclass.loadbalancer.LoadBalance;
import com.ydlclass.loadbalancer.Selector;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;

/**
 * 判断子节点是否发生变化的watcher
 * @Author duWenJian
 * @Date 2024/2/27 21:25
 * @Version 1.0
 */
@Slf4j
public class UpAndDownWatcher implements Watcher {
    @Override
    public void process(WatchedEvent event) {
        // 当前的节点发生了变化
        if (event.getType() == Event.EventType.NodeChildrenChanged){
            if (log.isDebugEnabled()){
                log.debug("检测到有节点上下线,将重新拉取服务列表");
            }
            // 检测节点发生改变
            String serviceName = getServiceName(event.getPath());
            List<InetSocketAddress> inetSocketAddressList = YrpcBootstrap.getInstance().getConfiguration().getRegistryConfig().getRegistry().lookup(serviceName,YrpcBootstrap.getInstance().getConfiguration().getGroup());
            for (InetSocketAddress address : inetSocketAddressList) {
                // 看是新加入的节点吗，
                if (!YrpcBootstrap.CHANNEL_CACHE.containsKey(address)){
                    // 新加入的节点建立连接，并加入缓存 todo 如果是在心跳检测之前掉线的节点，如何处理？
                    try {
                        Channel channel = NettyBootstrapInitializer.getBootstrap().connect(address).sync().channel();
                        YrpcBootstrap.CHANNEL_CACHE.put(address, channel);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

            // 处理下线的节点
            for (Map.Entry<InetSocketAddress,Channel> entry : YrpcBootstrap.CHANNEL_CACHE.entrySet()){
                if (!inetSocketAddressList.contains(entry.getKey())){
                    // 最新的数据列表，不包含当前节点，说明该节点已经掉线或者异常，应该在缓存将节点移除
                    YrpcBootstrap.CHANNEL_CACHE.remove(entry.getKey());
                }
            }

            // todo 进行节点变化考虑是否进行reBalance
            LoadBalance loadBalance = YrpcBootstrap.getInstance().getConfiguration().getLoadBalance();
            loadBalance.reLoadBalance(serviceName, inetSocketAddressList);
        }
    }

    private String getServiceName(String path) {
        String[] split = path.split("/");
        return split[split.length-1];
    }
}
